"""
SSE连接管理器 - 安全的Server-Sent Events实现
"""
import threading
import time
import queue
import logging
from typing import Dict, Optional, Any
from django.utils import timezone
from django.conf import settings

logger = logging.getLogger(__name__)


class SSEConnection:
    """SSE连接对象"""

    def __init__(self, user_id: int, connection_id: str):
        self.user_id = user_id
        self.connection_id = connection_id
        self.created_at = time.time()
        self.last_heartbeat = time.time()
        self.is_active = True
        self.message_queue = queue.Queue(maxsize=100)  # 限制队列大小防止内存泄漏

    def add_message(self, event_type: str, data: Any) -> bool:
        """添加消息到队列"""
        if not self.is_active:
            return False

        try:
            message = {
                'event': event_type,
                'data': data,
                'timestamp': timezone.now().isoformat()
            }
            self.message_queue.put_nowait(message)
            return True
        except queue.Full:
            logger.warning(f"用户 {self.user_id} 的消息队列已满，丢弃消息")
            return False
        except Exception as e:
            logger.error(f"添加消息到队列失败: {e}")
            return False

    def get_messages(self):
        """获取所有待发送消息"""
        messages = []
        try:
            while not self.message_queue.empty():
                messages.append(self.message_queue.get_nowait())
        except queue.Empty:
            pass
        return messages

    def update_heartbeat(self):
        """更新心跳时间"""
        self.last_heartbeat = time.time()

    def is_expired(self, timeout: int = 300) -> bool:
        """检查连接是否过期"""
        return time.time() - self.last_heartbeat > timeout

    def close(self):
        """关闭连接"""
        self.is_active = False


class SSEConnectionManager:
    """SSE连接管理器 - 单例模式"""

    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        if hasattr(self, '_initialized'):
            return

        self.connections: Dict[int, SSEConnection] = {}
        self.lock = threading.Lock()
        self.max_connections_per_user = getattr(settings, 'SSE_MAX_CONNECTIONS_PER_USER', 1)
        self.heartbeat_interval = getattr(settings, 'SSE_HEARTBEAT_INTERVAL', 30)
        self.connection_timeout = getattr(settings, 'SSE_CONNECTION_TIMEOUT', 300)
        self.cleanup_thread = None
        self.is_running = False
        self._initialized = True

        # 启动清理线程
        self.start_cleanup_thread()

    def add_connection(self, user_id: int, connection_id: str) -> SSEConnection:
        """添加SSE连接 - 强制单连接策略"""
        with self.lock:
            # 如果用户已有连接，先关闭旧连接
            if user_id in self.connections:
                old_connection = self.connections[user_id]
                old_connection.close()
                logger.info(f"关闭用户 {user_id} 的旧SSE连接")

            # 创建新连接
            connection = SSEConnection(user_id, connection_id)
            self.connections[user_id] = connection

            logger.info(f"用户 {user_id} 建立新SSE连接，当前总连接数: {len(self.connections)}")
            return connection

    def remove_connection(self, user_id: int):
        """移除SSE连接"""
        with self.lock:
            if user_id in self.connections:
                connection = self.connections[user_id]
                connection.close()
                del self.connections[user_id]
                logger.info(f"移除用户 {user_id} 的SSE连接，当前总连接数: {len(self.connections)}")

    def get_connection(self, user_id: int) -> Optional[SSEConnection]:
        """获取用户的SSE连接"""
        with self.lock:
            return self.connections.get(user_id)

    def is_connection_active(self, user_id: int, connection_id: str) -> bool:
        """检查指定用户的连接是否活跃"""
        connection = self.get_connection(user_id)
        if connection and connection.connection_id == connection_id:
            return connection.is_active
        return False

    def broadcast_to_user(self, user_id: int, event_type: str, data: Any) -> bool:
        """向特定用户广播消息"""
        connection = self.get_connection(user_id)
        if connection and connection.is_active:
            return connection.add_message(event_type, data)
        return False

    def broadcast_to_all(self, event_type: str, data: Any):
        """向所有连接的用户广播消息"""
        with self.lock:
            inactive_users = []
            for user_id, connection in self.connections.items():
                if connection.is_active:
                    success = connection.add_message(event_type, data)
                    if not success:
                        inactive_users.append(user_id)
                else:
                    inactive_users.append(user_id)

            # 清理无效连接
            for user_id in inactive_users:
                self.remove_connection(user_id)

    def send_heartbeat(self):
        """发送心跳到所有连接"""
        heartbeat_data = {
            'timestamp': timezone.now().isoformat(),
            'connection_count': len(self.connections)
        }
        self.broadcast_to_all('heartbeat', heartbeat_data)

    def cleanup_expired_connections(self):
        """清理过期连接"""
        with self.lock:
            expired_users = []
            for user_id, connection in self.connections.items():
                if connection.is_expired(self.connection_timeout):
                    expired_users.append(user_id)

            for user_id in expired_users:
                logger.info(f"清理过期连接: 用户 {user_id}")
                self.remove_connection(user_id)

    def start_cleanup_thread(self):
        """启动清理线程"""
        if not self.cleanup_thread or not self.cleanup_thread.is_alive():
            self.cleanup_thread = threading.Thread(target=self.cleanup_expired_connections, daemon=True)
            self.cleanup_thread.start()
            logger.info("SSE清理线程已启动")

    def stop_cleanup_thread(self):
        """停止清理线程"""
        self.is_running = False
        logger.info("SSE清理线程已停止")

    def _cleanup_worker(self):
        """清理工作线程 - 已禁用"""
        pass

    def get_status(self) -> Dict[str, Any]:
        """获取连接状态信息"""
        with self.lock:
            return {
                'total_connections': len(self.connections),
                'active_connections': sum(1 for conn in self.connections.values() if conn.is_active),
                'heartbeat_interval': self.heartbeat_interval,
                'connection_timeout': self.connection_timeout,
                'max_connections_per_user': self.max_connections_per_user,
                'cleanup_thread_running': self.is_running,
                'connections': {
                    user_id: {
                        'connection_id': conn.connection_id,
                        'created_at': conn.created_at,
                        'last_heartbeat': conn.last_heartbeat,
                        'is_active': conn.is_active,
                        'queue_size': conn.message_queue.qsize()
                    }
                    for user_id, conn in self.connections.items()
                }
            }

    def shutdown(self):
        """关闭管理器"""
        logger.info("正在关闭SSE连接管理器...")
        self.stop_cleanup_thread()

        with self.lock:
            for user_id, connection in self.connections.items():
                connection.close()
            self.connections.clear()

        logger.info("SSE连接管理器已关闭")


# 全局SSE连接管理器实例
sse_manager = SSEConnectionManager()
